package zsc.ruanc.practicaltraining.security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsUtils;
import zsc.ruanc.practicaltraining.security.Filter.SUsernamePasswordAuthenticationFilter;
import zsc.ruanc.practicaltraining.security.Filter.TokenFilter;
import zsc.ruanc.practicaltraining.security.components.UrlJudge;
import zsc.ruanc.practicaltraining.security.components.VoidPasswordEncode;
import zsc.ruanc.practicaltraining.security.handler.*;

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    @Qualifier("authUserDetailsServiceImpl")
    private UserDetailsService userDetailsService;

    @Autowired
    private TokenFilter tokenFilter;
    @Autowired
    private SAuthenticationEntryPoint myAuthenticationEntryPoint;
    @Autowired
    private SAccessDeniedHandler myAccessDeniedHandler;

    //登录成功处理器
    @Autowired
    private SAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    @Autowired
    private SAuthenticationFailureHandler myAuthenticationFailureHandler;


    @Autowired
    VoidPasswordEncode voidPasswordEncode;

    @Autowired
    UrlJudge dynamicPermission;


    //退出处理器
    @Autowired
    private SLogoutHandler myLogoutHandler;
    @Autowired
    private SLogoutSuccessHandler myLogoutSuccessHandler;

    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(voidPasswordEncode);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {


        //第1步：解决跨域问题。cors 预检请求放行,让Spring security 放行所有preflight request（cors 预检请求）
        http.authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll();

        //第2步：让Security永远不会创建HttpSession，它不会使用HttpSession来获取SecurityContext
        http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().headers().cacheControl();

        //第3步：请求权限配置
        //放行注册API请求，其它任何请求都必须经过身份验证.
        http.authorizeRequests()
                .antMatchers("/login", "/user/create", "/user/findPassword", "/test/**", "/user/getInfo",
                        "/email/sendCode", "/email/sendFindPasswordCode", "/res/**",
                        "/article/get/{id}", "/article/vagueQuery", "/article/userArticleList", "/article/recommend", "/article/getAllTrue", "/article/selectCategories",
                        "/comment/commentPage", "/class/selectPage", "/class/getNameList","/class/selectByName").permitAll()
                .anyRequest().access("authenticated and @urlJudge.check(request,authentication)");
//                .anyRequest().access("@urlJudge.check(request,authentication)");


        //第4步：拦截账号、密码。覆盖 UsernamePasswordAuthenticationFilter过滤器
        http.addFilterAt(myUsernamePasswordAuthenticationFilter() , UsernamePasswordAuthenticationFilter.class);

        //第5步：拦截token，并检测。在 UsernamePasswordAuthenticationFilter 之前添加 JwtAuthenticationTokenFilter
        http.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class);

        //第6步：处理异常情况：认证失败和权限不足
        http.exceptionHandling().authenticationEntryPoint(myAuthenticationEntryPoint).accessDeniedHandler(myAccessDeniedHandler);

        //第7步：登录,因为使用前端发送JSON方式进行登录，所以登录模式不设置也是可以的。
        http.formLogin();

        //第8步：退出
        http.logout().addLogoutHandler(myLogoutHandler).logoutSuccessHandler(myLogoutSuccessHandler);


    }


    @Override
    public void configure(WebSecurity web){
        web.ignoring().antMatchers("/js/**");
        web.ignoring().antMatchers("/css/**");
        web.ignoring().antMatchers("/static/**");
        web.ignoring().antMatchers("/img/**");
        web.ignoring().antMatchers("/swagger-ui.html");
        web.ignoring().antMatchers("/webjars/**");
        web.ignoring().antMatchers("/v2/**");
        web.ignoring().antMatchers("/swagger-resources/**");
//        web.ignoring().antMatchers("/res/**");

    }



    /**
     * 手动注册账号、密码拦截器
     * @return
     * @throws Exception
     */
    @Bean
    SUsernamePasswordAuthenticationFilter myUsernamePasswordAuthenticationFilter() throws Exception {
        SUsernamePasswordAuthenticationFilter filter = new SUsernamePasswordAuthenticationFilter();
        //成功后处理
        filter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);
        //失败后处理
        filter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);

        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }




}
